using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;

using EMan.Common;
using EMan.Common.DependencyInjection;
using EMan.Common.EnterpriseStructure;
using EMan.Server.Interface.DAL;

using TrueCode.Core.Aspects;
using TrueCode.Core.Validation;

namespace EMan.Server.BL
{
  public class EManImpl : IEMan
  {
    private readonly IValidator _validator;
    private readonly IFactory _factory;

    public EManImpl( [NotNull] IValidator validator, [NotNull] IFactory factory )
    {
      #region Validation
      if( validator == null ) throw new ArgumentNullException( "validator" );
      if( factory == null ) throw new ArgumentNullException( "factory" );
      #endregion

      _validator = validator;
      _factory = factory;
    }

    #region Implementation of IEnterpriseStructure
    public IEnumerable< Job > GetAllJobs()
    {
      using( var dalc = _factory.Resolve< IDalc< Job > >() )
        return dalc.GetList();
    }

    public Changeset< Job > UpdateJobs( Changeset< Job > changeset )
    {
      using( var ts = new TransactionScope())
      using( var dalc = _factory.Resolve< IDalc< Job > >() )
      {
        foreach( var job in changeset.Added.Concat( changeset.Modified ) )
          _validator.Validate( job );

        foreach( var job in changeset.Added )
          dalc.Insert( job );

        foreach( var job in changeset.Modified )
          dalc.Update( job );

        foreach( var jobId in changeset.Deleted )
          dalc.Delete( jobId );

        ts.Complete();
      }
      return changeset;
    }


    public IList< Department > GetAllDepartments()
    {
      using( var departmentDalc = _factory.Resolve< IDalc< Department > >() )
      using( var employeeDalc = _factory.Resolve< IEmployeeDalc >() )
      {
        var departments = departmentDalc.GetList();
        foreach( var department in departments )
        {
          foreach( var employee in employeeDalc.GetListByDepartment( department.Id ) )
          {
            employee.Department = department;
            department.Add( employee );
          }
        }

        return departments;
      }
    }

    public StructureChangeset UpdateStructure( StructureChangeset changeset )
    {
      Console.WriteLine( "UpdateStructure start" );

      using( var ts = new TransactionScope() )
      using( var dalc = _factory.Resolve< IDalc< Department > >() )
      {
        foreach( var department in changeset.NewDepartments )
          dalc.Insert( department );

        foreach( var department in changeset.ModifiedDepartments )
          dalc.Update( department );

        // Order deleted departments by their id descending. Parent department can't have an id greater than sub-department, so
        // we will delete-sub departments first and avoid FK violation exception
        foreach( var deletedDepartmentId in changeset.DeletedDepartments )
          dalc.Delete( deletedDepartmentId );

        ts.Complete();
      }
      Console.WriteLine( "UpdateStructure end" );
      return changeset;
    }
    #endregion
  }
}